﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Lowpass filter. 
    /// A lowpassfilter lets only pass low frequencies.
    /// This happens to get a blurred image as a result.
    /// </summary>
    public class Lowpass : BaseImageFilter
    {
        protected int m_nWeight = 10;
        protected int m_nZ = 3;

        /// <summary>
        /// Initializes a new instance of the <see cref="Lowpass"/> class.
        /// </summary>
        public Lowpass()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Lowpass"/> class.
        /// </summary>
        /// <param name="_nZ">The _n Z.</param>
        /// <param name="_nWeight">The _n weight.</param>
        public Lowpass(int _nZ, int _nWeight)
        {
            m_nZ = _nZ;
            m_nWeight = _nWeight; //1 means no weight
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Lowpass"/> class.
        /// </summary>
        /// <param name="_lowpass">The _lowpass.</param>
        internal Lowpass(Lowpass _lowpass)
        {
            this.m_nZ = _lowpass.m_nZ;
            this.m_nWeight = _lowpass.m_nWeight;
        }


        /// <summary>
        /// Gets or sets the weight.
        /// </summary>
        /// <value>The weight.</value>
        public int Weight
        {
            get { return m_nWeight; }
            set { m_nWeight = value; }
        }

        /// <summary>
        /// Gets or sets the Z.
        /// </summary>
        /// <value>The Z.</value>
        public int Z
        {
            get { return m_nZ; }
            set { m_nZ = value; }
        }

        /// <summary>
        /// Execute the lowpass filter
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nSumLeft = 0;
            int nSumRight = 0;
            int nSumTop = 0;
            int nSumBottom = 0;
            int nDivisor = 0;

            int nSum = 0;

            UnsafeBitmap bitmap = _bitmap;
            UnsafeBitmap bitmapTemp = (UnsafeBitmap)_bitmap.Clone();

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            int y = 0;
            int x = 0;
            Color color = Color.Transparent;

            int nYWindow = 0;
            int nXWindow = 0;
            int nValue = 0;

            int[,] aGray = new int[nWidth, nHeight];

            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    aGray[x, y] = _bitmap.GetGrayPixelValue(x, y);
                }
            }

            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    color = bitmapTemp.GetPixel(x, y);
                    nDivisor = m_nWeight - 1; //MidWeight == 1 means no weight
                    nSum = nDivisor * ColorFunctions.Gray(color);
                    for (nYWindow = y - m_nZ; nYWindow <= y + m_nZ; nYWindow++)
                    {
                        if (nYWindow < 0 || nYWindow >= nHeight) continue;
                        for (nXWindow = x - m_nZ; nXWindow <= x + m_nZ; nXWindow++)
                        {
                            if (nXWindow < 0 || nXWindow >= nWidth) continue;
                            nSum += aGray[nXWindow, nYWindow]; //ColorFunctions.Gray(bitmapTemp.GetPixel(nXWindow, nYWindow));
                            nDivisor++;
                        }
                    }
                    nValue = Convert.ToByte((float)nSum / (float)nDivisor);
                    bitmap.SetPixel(x, y, Color.FromArgb(nValue, nValue, nValue));
                }
            }
            bitmapTemp.Dispose();
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Lowpass(this);
        }
    }
}
